version: 2

# A reusable "run" snippet which is ran before each test to setup the
# environment for user-limits, core-dumps, etc.
run_env_change: &run_env_change
  name: Environment Changes
  command: |
    # Make a place to core dumps to live.
    sudo mkdir -p /tmp/core_dumps
    sudo chmod a+rwx /tmp/core_dumps

    # Bake the locale we expect into the image.
    echo "en_US.UTF-8 UTF-8" | sudo tee /etc/locale.gen
    sudo locale-gen

    # The commands below don't work in Docker images, but might be worth
    # reenabling if we switch back to machine:true instead of Docker.

    # Set the pattern for core dumps, so we can find them.
    # echo kernel.core_pattern="/tmp/core_dumps/core.%e.%p.%h.%t" | \
    #     sudo tee -a /etc/sysctl.conf

    # Note that since every "run" command starts its own shell, and I wasn't
    # able to set this at a system wide level for all users, it's necessary to
    # run "ulimit -c unlimited" before each command which you want to (possibly)
    # output a core dump.

    # Raise inotify user watches up higher.
    # echo fs.inotify.max_user_watches=524288 | \
    #     sudo tee -a /etc/sysctl.conf

    # Reload sysctl so these are in effect.
    # sudo sysctl -p

# A reusable "run" snippet which enables the continued logging of memoryusage
# to a file on disk which can be saved to build artifacts for later analysis.
run_log_mem_use: &run_log_mem_use
  background: true
  name: Setup Memory Logging
  command: |
    # Log memory usage throughout entire build.
    MEMUSELOG=/tmp/memuse.txt /bin/bash -c '\
        while true; do\
          ps -e -o user,%cpu,%mem,rss:10,vsz:10,command:20 \
            --sort=-%mem >> $MEMUSELOG; \
          echo "----------" >> $MEMUSELOG; \
          sleep 1; \
        done'

# A reusable "run" snippet for saving the Node binary if a core dump is present.
run_save_node_bin: &run_save_node_bin
  name: Save Node Binary
  when: on_fail
  command: |
    if compgen -G "/tmp/core_dumps/core.*" > /dev/null; then
      echo "Saving Node binary since Core dump is present..."
      cp dev_bundle/bin/node /tmp/core_dumps/node
    fi

# This environment is set to every job (and the initial build).
build_machine_environment: &build_machine_environment
  # Specify that we want an actual machine (ala Circle 1.0), not a Docker image.
  docker:
    - image: meteor/circleci
  environment:
    # This multiplier scales the waitSecs for selftests.
    TIMEOUT_SCALE_FACTOR: 8

    # Retry failed tests additional times.
    METEOR_SELF_TEST_RETRIES: 2

    # These, mostly overlapping, flags ensure that CircleCI is as pretty as
    # possible for a non-interactive environment.  See also: --headless.
    METEOR_HEADLESS: true
    METEOR_PRETTY_OUTPUT: 0

    # In an effort to stop SIGSEGV, this just doesn't bother cleaning up
    # the mess of temp directories that Meteor makes.
    METEOR_SAVE_TMPDIRS: 1

    # Skip these tests on every test run.
    # If needed, for readability this should be a regex wrapped across
    # multiple lines in quotes.
    SELF_TEST_EXCLUDE: "add debugOnly and prodOnly packages"

    # These will be evaled before each command.
    PRE_TEST_COMMANDS: |-
        ulimit -c unlimited; # Set core dump size as Ubuntu 14.04 lacks prlimit.
        ulimit -a # Display all ulimit settings for transparency.

    # This is only to make Meteor self-test not remind us that we can set
    # this argument for self-tests.
    SELF_TEST_TOOL_NODE_FLAGS: " "

    # Variables for load-balancing
    NUM_GROUPS: 11
    RUNNING_AVG_LENGTH: 5

jobs:
  Get Ready:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - checkout
      - run:
          # https://discuss.circleci.com/t/git-submodule-url-isnt-playing-nice-with-the-cache/549/3
          name: Git Submodules.
          command: (git submodule sync && git submodule update --init --recursive) || (rm -fr .git/config .git/modules && git submodule deinit -f . && git submodule update --init --recursive)
      - restore_cache:
          keys:
            - v1-dev-bundle-cache-{{ checksum "meteor" }}
            - v1-dev-bundle-cache-
      - restore_cache:
          keys:
            - v2-other-deps-cache-{{ .Branch }}-{{ .Revision }}
            - v2-other-deps-cache-{{ .Branch }}-
      - restore_cache:
          keys: 
            - v1-test-groups-{{ .Branch }}
            - v1-test-groups-
      - run:
          name: Create Test Results Directory
          command: |
            sudo mkdir -p ./tmp/results/junit
            sudo chmod a+rwx ./tmp/results/junit
      # Clear dev_bundle/.npm to ensure consistent test runs.
      - run:
          name: Clear npm cache
          command: ./meteor npm cache clear --force
      - run:
          name: Get Ready
          command: |
            eval $PRE_TEST_COMMANDS;
            ./meteor --get-ready
          # shouldn't take longer than 20 minutes
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - persist_to_workspace:
          root: .
          paths: .
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Isolated Tests:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test ('package-tests: add debugOnly and prodOnly packages')"
          command: |
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              'add debugOnly and prodOnly packages' \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --headless
          no_output_timeout: 20m
      - run:
          name: "Running self-test (Custom Warehouse Tests)"
          command: |
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --with-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 0:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 0)"
          command: |
            if [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=$(<./tmp/test-groups/0.txt); else TEST_GROUP='^[a-b]|^c[a-n]|^co[a-l]|^comm'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/0.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 1:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 1)"
          command: |
            if [ -f ./tmp/test-groups/1.txt ]; then TEST_GROUP=$(<./tmp/test-groups/1.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^com[n-z]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/1.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 2:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 2)"
          command: |
            if [ -f ./tmp/test-groups/2.txt ]; then TEST_GROUP=$(<./tmp/test-groups/2.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^co[n-z]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/2.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 3:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 3)"
          command: |
            if [ -f ./tmp/test-groups/3.txt ]; then TEST_GROUP=$(<./tmp/test-groups/3.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^c[p-z]|^[d-g]|^h[a-e]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/3.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 4:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 4)"
          command: |
            if [ -f ./tmp/test-groups/4.txt ]; then TEST_GROUP=$(<./tmp/test-groups/4.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^h[f-z]|^[i-l]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/4.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 5:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 5)"
          command: |
            if [ -f ./tmp/test-groups/5.txt ]; then TEST_GROUP=$(<./tmp/test-groups/5.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^m[a-n]|^mo[a-d]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/5.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt
 
  Test Group 6:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 6)"
          command: |
            if [ -f ./tmp/test-groups/6.txt ]; then TEST_GROUP=$(<./tmp/test-groups/6.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^mo[e-z]|^m[p-z]|^[n-o]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/6.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 7:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 7)"
          command: |
            if [ -f ./tmp/test-groups/7.txt ]; then TEST_GROUP=$(<./tmp/test-groups/7.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^[p-q]|^r[a-e]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/7.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 8:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 8)"
          command: |
            if [ -f ./tmp/test-groups/8.txt ]; then TEST_GROUP=$(<./tmp/test-groups/8.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^r[f-z]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/8.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 9:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 9)"
          command: |
            if [ -f ./tmp/test-groups/9.txt ]; then TEST_GROUP=$(<./tmp/test-groups/9.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^s'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/9.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  Test Group 10:
    <<: *build_machine_environment
    steps:
      - run:
          <<: *run_log_mem_use
      - run:
          <<: *run_env_change
      - attach_workspace:
          at: .
      - run:
          name: "Print environment"
          command: printenv
      - run:
          name: "Running self-test (Test Group 10)"
          command: |
            if [ -f ./tmp/test-groups/10.txt ]; then TEST_GROUP=$(<./tmp/test-groups/10.txt); elif [ -f ./tmp/test-groups/0.txt ]; then TEST_GROUP=XXXXX; else TEST_GROUP='^[t-z]'; fi
            echo $TEST_GROUP;
            eval $PRE_TEST_COMMANDS;
            ./meteor self-test \
              "$TEST_GROUP" \
              --retries ${METEOR_SELF_TEST_RETRIES} \
              --exclude "${SELF_TEST_EXCLUDE}" \
              --headless \
              --junit ./tmp/results/junit/10.xml \
              --without-tag "custom-warehouse"
          no_output_timeout: 20m
      - run:
          <<: *run_save_node_bin
      - store_test_results:
          path: ./tmp/results
      - persist_to_workspace:
          root: .
          paths: ./tmp/results/junit
      - store_artifacts:
          path: ./tmp/results
      - store_artifacts:
          path: /tmp/core_dumps
      - store_artifacts:
          path: /tmp/memuse.txt

  # Test the JSDoc declarations which live within this codebase against the
  # Meteor Docs (https://github.com/meteor/docs) repository, where they'll
  # eventually be consumed.  This test aims to provide an early warning of
  # potentially breaking changes, so they aren't discovered when the docs are
  # next updated, which generally occurs during major Meteor version releases
  # (for example, 1.4 to 1.5, 1.5 to 1.6).
  Docs:
    docker:
      # This Node version should match that in the meteor/docs CircleCI config.
      - image: circleci/node:8
    environment:
      CHECKOUT_METEOR_DOCS: /home/circleci/test_docs
    steps:
      - run:
          name: Cloning "meteor/docs" Repository's "master" branch
          command: |
            git clone https://github.com/meteor/docs.git ${CHECKOUT_METEOR_DOCS}
      # The "docs" repository normally brings in the Meteor code as a Git
      # submodule checked out into the "code" directory.  As the goal of this
      # test is to run it against the _current_ repository's code, we'll move
      # the "code" directory out of the way and move the checkout (of meteor)
      # into that directory, rather than the default $CIRCLE_WORKING_DIRECTORY.
      - checkout
      - run:
          name: Move Meteor checkout into docs repository's "code" directory
          command: |
            rmdir "${CHECKOUT_METEOR_DOCS}/code"
            # $CIRCLE_WORKING_DIRECTORY uses a tilde, so expand it to $HOME.
            mv "${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}" \
              "${CHECKOUT_METEOR_DOCS}/code"
      # Run almost the same steps the meteor/docs repository runs, minus deploy.
      - run:
          name: Generating Meteor documentation for JSDoc testing
          command: |
            cd ${CHECKOUT_METEOR_DOCS}
            npm install
            npm test

  Clean Up:
    <<: *build_machine_environment
    steps:
      - attach_workspace:
          at: .
      - run:
          name: Create Test Groups Directory
          command: |
            sudo mkdir -p ./tmp/test-groups
            sudo chmod a+rwx ./tmp/test-groups
      - run:
          name: Calculate Balanced Test Groups
          command: |
            npm install --prefix ./scripts/test-balancer
            npm start --prefix ./scripts/test-balancer --num-groups ${NUM_GROUPS} --running-avg-length ${RUNNING_AVG_LENGTH}
      - save_cache:
          key: v1-test-groups-{{ .Branch }}-{{ .BuildNum }}
          paths:
            - ./tmp/test-groups
          when: on_success
      - save_cache:
          key: v1-dev-bundle-cache-{{ checksum "meteor" }}
          paths:
            - "dev_bundle"
      - save_cache:
          key: v2-other-deps-cache-{{ .Branch }}-{{ .Revision }}
          paths:
            - ".babel-cache"
            - ".meteor"

workflows:
  version: 2
  Build and Test:
    jobs:
      - Docs
      - Get Ready
      - Isolated Tests:
          requires:
            - Get Ready
      - Test Group 0:
          requires:
            - Get Ready
      - Test Group 1:
          requires:
            - Get Ready
      - Test Group 2:
          requires:
            - Get Ready
      - Test Group 3:
          requires:
            - Get Ready
      - Test Group 4:
          requires:
            - Get Ready
      - Test Group 5:
          requires:
            - Get Ready
      - Test Group 6:
          requires:
            - Get Ready
      - Test Group 7:
          requires:
            - Get Ready
      - Test Group 8:
          requires:
            - Get Ready
      - Test Group 9:
          requires:
            - Get Ready
      - Test Group 10:
          requires:
            - Get Ready
      - Clean Up:
          requires:
            - Isolated Tests
            - Test Group 0
            - Test Group 1
            - Test Group 2
            - Test Group 3
            - Test Group 4
            - Test Group 5
            - Test Group 6
            - Test Group 7
            - Test Group 8
            - Test Group 9
            - Test Group 10
